﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;

namespace SMS_Server_Manager
{
    public partial class SplashScreen : Form
    {
        public SplashScreen()
        {
            InitializeComponent();
        }

        private void SplashScreen_Load(object sender, EventArgs e)
        {
            Thread th = new Thread(StartLoading);
            th.Start();
        }

        private delegate void IntParam(int number);
        private delegate void StringParam(string str);

        private void StartLoading()
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            if (path[path.Length - 1] == '\\') path = path.Substring(0, path.Length - 1);

            IntParam up = new IntParam(UpdateProgress);
            IntParam uop = new IntParam(UpdateOverAllProgress);
            StringParam us = new StringParam(UpdateStatus);
            StringParam SM = new StringParam(ShowMessage);
            StringParam LF = new StringParam(LoadForm);

            this.Invoke(us, new object[] { "Checking directory..." });
            if (!System.IO.Directory.Exists(path + "\\Config"))
            {
                this.Invoke(us, new object[] { "Creating Directory..." });
                System.IO.Directory.CreateDirectory(path + "\\Config");
            }
            this.Invoke(us, new object[] { "Checking directory..." });
            if (!System.IO.Directory.Exists(path + "\\App_Data"))
            {
                this.Invoke(us, new object[] { "Creating Directory..." });
                System.IO.Directory.CreateDirectory(path + "\\App_Data");
            }
            this.Invoke(us, new object[] { "Generating Identity..." });
            //string MachineID = License_Manager.MachineIdentity.GetMachineIdentity();
            this.Invoke(up, new object[] { 100 });
            this.Invoke(uop, new object[] { 10 });
            this.Invoke(us, new object[] { "Checking file..." });
            if (!System.IO.File.Exists(path + "\\config\\config.src"))
            {
                try
                {
                    this.Invoke(us, new object[] { "Connecting to Onuprova..." });
                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://onuprova.com/downloads/config.sdf");
                    req.Method = "GET";
                    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                    Stream respStream = resp.GetResponseStream();
                    this.Invoke(us, new object[] { "Downloading Config.src..." });

                    int count = 0;
                    long total = resp.ContentLength;
                    long tillNow = 0;
                    byte[] buff = new byte[1024];
                    FileStream fs = new FileStream(path + "\\config\\config.src", FileMode.Create, FileAccess.Write);
                    //SMS_Server.FileSecurity security = new SMS_Server.FileSecurity();

                    while (true)
                    {
                        count = respStream.Read(buff, 0, buff.Length);
                        if (count == 0) break;

                        if (count == buff.Length)
                        {
                            //byte[] newBuff = security.DeltaMultiply(buff, MachineID);
                            fs.Write(buff, 0, count);
                        }
                        else
                        {
                            byte[] secbuff = new byte[count];
                            for (int i = 0; i < count; i++)
                            {
                                secbuff[i] = buff[i];
                            }
                            //byte[] newBuff = security.DeltaMultiply(secbuff, MachineID);
                            fs.Write(secbuff, 0, count);
                        }
                        tillNow += count;
                        this.Invoke(up, new object[] { (int)(tillNow / total) * 100 });
                    }
                    fs.Close();
                    resp.Close();
                    req.Abort();
                }
                catch
                {
                    this.Invoke(SM, new object[] { "Network error. Please check the internet connection and re-start the application." });
                    return;
                }
            }
            this.Invoke(uop, new object[] { 20 });

            //now Generate sdf and continue
            string ConfigFile = path + "\\App_data\\ManageConfig.sdf";
            if (System.IO.File.Exists(ConfigFile))
            {
                this.Invoke(us, new object[] { "Clearing cache..." });
                try
                {
                    System.IO.File.Delete(ConfigFile);
                }
                catch
                {
                    this.Invoke(SM, new object[] { "An instance of Server Manager is already runing. Please re-start the computer and try again." });
                    return;
                }
            }

            this.Invoke(us, new object[] { "Generating cache..." });

            try
            {
                FileStream Sourcefs = new FileStream(path + "\\config\\config.src", FileMode.Open, FileAccess.Read);
                FileStream Destinationfs = new FileStream(ConfigFile, FileMode.Create, FileAccess.Write);

                int counter = 0;
                long totall = Sourcefs.Length;
                long tillnow = 0;
                byte[] buffer = new byte[1024];

                //SMS_Server.FileSecurity file_security = new SMS_Server.FileSecurity();

                while (true)
                {
                    counter = Sourcefs.Read(buffer, 0, buffer.Length);
                    if (counter == 0) break;

                    if (counter == buffer.Length)
                    {
                        //byte[] newBuff = file_security.DeltaMultiply(buffer, MachineID);
                        Destinationfs.Write(buffer, 0, counter);
                    }
                    else
                    {
                        byte[] secbuff = new byte[counter];
                        for (int i = 0; i < counter; i++)
                        {
                            secbuff[i] = buffer[i];
                        }
                        //byte[] newBuff = file_security.DeltaMultiply(secbuff, MachineID);
                        Destinationfs.Write(secbuff, 0, counter);
                    }
                    tillnow += counter;
                    this.Invoke(up, new object[] { (int)(tillnow / totall) * 100 });
                }
                Destinationfs.Close();
                Sourcefs.Close();
            }
            catch
            {
                this.Invoke(SM, new object[] { "Caching error, Please re-start the computer and try again." });
                return;
            }

            string usageDatabase = path + "\\App_data\\Usages.sdf";
            if (!File.Exists(usageDatabase))
            {
                FileStream fs=new FileStream(usageDatabase, FileMode.Create, FileAccess.Write);
                fs.Write(Properties.Resources.Usages, 0, Properties.Resources.Usages.Length);
                fs.Close();
            }

            this.Invoke(uop, new object[] { 30 });

            this.Invoke(us, new object[] { "Loading functions..." });
            this.Invoke(up, new object[] { 0 });
            //lets load the functions and actions here
            DataAccess DA = new DataAccess(Global.GetConfigurationDatabaseName(), Global.DatabasePassword);
            DA.CommandString = "SELECT * FROM Functions";
            try
            {
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    string FunctionName = DA.Reader.GetString(0);
                    long FunctionID = DA.Reader.GetInt64(1);
                    string ParamFormat = DA.Reader.GetString(2);
                    SMS_Server.Function function = new SMS_Server.Function();
                    function.FunctionName = FunctionName;
                    function.FunctionID = (int)FunctionID;
                    function.ParamFormat = ParamFormat;
                    function.Actions = new List<SMS_Server.Incoming_Action>();
                    Global.Functions.Add(function);
                }
                SMS_Server.Function nf = new SMS_Server.Function();
                nf.FunctionName = "Unknown";
                nf.FunctionID = 0;
                nf.ParamFormat = "";
                Global.Functions.Add(nf);
                DA.Reader.Close();
            }
            catch
            {
                //could not be loaded so the 
                System.IO.File.Delete(path + "\\config\\config.src");
                this.Invoke(SM, new object[] { "Cleaning up old data. Please restart the application. Your configuration data will be lost." });
                return;
            }
            int functioncount = 0;
            foreach (SMS_Server.Function f in Global.Functions)
            {
                //Load static response actions
                DA.ClearParameters();
                DA.CommandString = "SELECT * FROM Action_Static WHERE FunctionName=@FunctionName;";
                DA.AddParameter("@FunctionName", f.FunctionName);
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    SMS_Server.Action_StaticResponse aS = new SMS_Server.Action_StaticResponse();
                    aS.ActionFormat = f.ParamFormat;
                    aS.ActionName = f.FunctionName;
                    aS.ResponseString = DA.Reader.GetString(2);
                    aS.actionID = (int)DA.Reader.GetInt64(3);
                    f.Actions.Add(aS);
                }
                DA.Reader.Close();
                this.Invoke(up, new object[] { (int)((decimal)(((decimal)functioncount + (1 / 6)) / Global.Functions.Count) * 100) });
                this.Invoke(uop, new object[] { 30 + (int)((decimal)(((decimal)functioncount + (1 / 6)) / Global.Functions.Count) * 50) });

                //Load sms email actions
                DA.ClearParameters();
                DA.CommandString = "SELECT * FROM Action_SMS_Email WHERE FunctionName=@FunctionName;";
                DA.AddParameter("@FunctionName", f.FunctionName);
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    SMS_Server.Action_SMS_Email se = new SMS_Server.Action_SMS_Email();
                    se.ActionFormat = f.ParamFormat;
                    se.ActionName = f.FunctionName;
                    se.Address = DA.Reader.GetString(2);
                    string mode = DA.Reader.GetString(3);
                    if (mode.ToUpper() == "SMS") se.Mode = SMS_Server.Action_SMS_Email.SendingMode.SMS; else se.Mode = SMS_Server.Action_SMS_Email.SendingMode.EMAIL;
                    se.actionID = (int)DA.Reader.GetInt64(4);
                    f.Actions.Add(se);
                }
                DA.Reader.Close();
                this.Invoke(up, new object[] { (int)((decimal)(((decimal)functioncount + (2 / 6)) / Global.Functions.Count) * 100) });
                this.Invoke(uop, new object[] { 30 + (int)((decimal)(((decimal)functioncount + (2 / 6)) / Global.Functions.Count) * 50) });

                //Load toHTTP actions
                DA.ClearParameters();
                DA.CommandString = "SELECT * FROM Action_ToHTTP WHERE FunctionName=@FunctionName;";
                DA.AddParameter("@FunctionName", f.FunctionName);
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    SMS_Server.Action_Forward2HTTP th = new SMS_Server.Action_Forward2HTTP();
                    th.ActionFormat = f.ParamFormat;
                    th.ActionName = f.FunctionName;
                    th.URL = DA.Reader.GetString(2);
                    string method = DA.Reader.GetString(3).ToUpper();
                    if (method == "GET") th.Method = SMS_Server.Action_Forward2HTTP.HttpMetod.GET; else th.Method = SMS_Server.Action_Forward2HTTP.HttpMetod.POST;
                    th.HasResponse = DA.Reader.GetBoolean(4);
                    th.actionID = (int)DA.Reader.GetInt64(5);
                    f.Actions.Add(th);
                }
                DA.Reader.Close();
                this.Invoke(up, new object[] { (int)((decimal)(((decimal)functioncount + (3 / 6)) / Global.Functions.Count) * 100) });
                this.Invoke(uop, new object[] { 30 + (int)((decimal)(((decimal)functioncount + (3 / 6)) / Global.Functions.Count) * 50) });

                //Load toTCP actions
                DA.ClearParameters();
                DA.CommandString = "SELECT * FROM Action_ToTCP WHERE FunctionName=@FunctionName;";
                DA.AddParameter("@FunctionName", f.FunctionName);
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    SMS_Server.Action_Forward2TCP tt = new SMS_Server.Action_Forward2TCP();
                    tt.ActionFormat = f.ParamFormat;
                    tt.ActionName = f.FunctionName;
                    tt.IP = DA.Reader.GetString(2);
                    tt.Port = DA.Reader.GetInt32(3);
                    tt.HasResponse = DA.Reader.GetBoolean(4);
                    tt.actionID = (int)DA.Reader.GetInt64(5);
                    f.Actions.Add(tt);
                }
                DA.Reader.Close();
                this.Invoke(up, new object[] { (int)((decimal)(((decimal)functioncount + (4 / 6)) / Global.Functions.Count) * 100) });
                this.Invoke(uop, new object[] { 30 + (int)((decimal)(((decimal)functioncount + (4 / 6)) / Global.Functions.Count) * 50) });

                //Load Search actions
                DA.ClearParameters();
                DA.CommandString = "SELECT * FROM Action_Search WHERE FunctionName=@FunctionName;";
                DA.AddParameter("@FunctionName", f.FunctionName);
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    SMS_Server.Action_Search sf = new SMS_Server.Action_Search();
                    sf.ActionFormat = f.ParamFormat;
                    sf.ActionName = f.FunctionName;
                    string connector = DA.Reader.GetString(2).ToUpper();
                    if (connector == "OLEDB") sf.Connector = SMS_Server.Action_Search.Connectors.OleDb; else if (connector == "ODBC") sf.Connector = SMS_Server.Action_Search.Connectors.Odbc; else sf.Connector = SMS_Server.Action_Search.Connectors.SQL;
                    sf.ConnectionString = DA.Reader.GetString(3);
                    sf.TableName = DA.Reader.GetString(4);
                    sf.SearchColumns = DA.Reader.GetString(5);
                    sf.ResponseColumns = DA.Reader.GetString(6);
                    sf.ResponseFormat = DA.Reader.GetString(7);
                    sf.actionID = (int)DA.Reader.GetInt64(8);
                    f.Actions.Add(sf);
                }
                DA.Reader.Close();
                this.Invoke(up, new object[] { (int)((decimal)(((decimal)functioncount + (5 / 6)) / Global.Functions.Count) * 100) });
                this.Invoke(uop, new object[] { 30 + (int)((decimal)(((decimal)functioncount + (5 / 6)) / Global.Functions.Count) * 50) });

                //Load Insert actions
                DA.ClearParameters();
                DA.CommandString = "SELECT * FROM Action_Insert WHERE FunctionName=@FunctionName;";
                DA.AddParameter("@FunctionName", f.FunctionName);
                DA.ExecuteReader();
                while (DA.Reader.Read())
                {
                    SMS_Server.Action_Insert ii = new SMS_Server.Action_Insert();
                    ii.ActionFormat = f.ParamFormat;
                    ii.ActionName = f.FunctionName;
                    string connector = DA.Reader.GetString(2).ToUpper();
                    if (connector == "OLEDB") ii.Connector = SMS_Server.Action_Insert.Connectors.OleDb; else if (connector == "ODBC") ii.Connector = SMS_Server.Action_Insert.Connectors.Odbc; else ii.Connector = SMS_Server.Action_Insert.Connectors.SQL;
                    ii.ConnectionString = DA.Reader.GetString(3);
                    ii.TableName = DA.Reader.GetString(4);
                    ii.Columns = DA.Reader.GetString(5);
                    ii.HasResponse = DA.Reader.GetBoolean(6);
                    ii.ResponseColumns = DA.Reader.GetString(7);
                    ii.ResponseFormat = DA.Reader.GetString(8);
                    ii.actionID = (int)DA.Reader.GetInt64(9);
                    f.Actions.Add(ii);
                }
                DA.Reader.Close();
                this.Invoke(up, new object[] { (int)((decimal)(((decimal)functioncount + (6 / 6)) / Global.Functions.Count) * 100) });
                this.Invoke(uop, new object[] { 30 + (int)((decimal)(((decimal)functioncount + (6 / 6)) / Global.Functions.Count) * 50) });

                functioncount++;
            }


            //*************************************************************************************

            this.Invoke(us, new object[] { "Loading configuration..." });
            this.Invoke(up, new object[] { 0 });

            //Read IMEI
            DA.ClearParameters();
            DA.CommandString = "SELECT ParamValue FROM General_Config WHERE ParamName=@ParamName;";
            DA.AddParameter("@ParamName", "IMEI");
            DA.ExecuteReader();
            if (DA.Reader.Read())
            {
                Global.IMEI = DA.Reader.GetString(0);
                DA.Reader.Close();
            }
            else
            {
                DA.Reader.Close();
                DA.ClearParameters();
                DA.CommandString = "INSERT INTO General_Config (ParamName, ParamValue) VALUES (@ParamName, @ParamValue);";
                DA.AddParameter("@ParamName", "IMEI");
                DA.AddParameter("@ParamValue", "");
                DA.ExecuteNonQuery();
            }

            //Read AllowedCountryCodes
            DA.ClearParameters();
            DA.CommandString = "SELECT ParamValue FROM General_Config WHERE ParamName=@ParamName;";
            DA.AddParameter("@ParamName", "AllowedCountryCodes");
            DA.ExecuteReader();
            if (DA.Reader.Read())
            {
                Global.AllowedCountryCodes = DA.Reader.GetString(0);
                DA.Reader.Close();
            }
            else
            {
                DA.Reader.Close();
                DA.ClearParameters();
                DA.CommandString = "INSERT INTO General_Config (ParamName, ParamValue) VALUES (@ParamName, @ParamValue);";
                DA.AddParameter("@ParamName", "AllowedCountryCodes");
                DA.AddParameter("@ParamValue", "");
                DA.ExecuteNonQuery();
            }
            //close the database as the database is no longer in need
            DA.Close();
            this.Invoke(up, new object[] { 45 });

            this.Invoke(us, new object[] { "Validating configuration..." });
            //License loaded now validate license
            this.Invoke(up, new object[] { 100 });
            this.Invoke(uop, new object[] { 100 });

                this.Invoke(LF, new object[] { "MainForm" });
                return;
        }

        private void UpdateProgress(int progress)
        {
            Progress.Text = progress + "%";
        }

        private void UpdateOverAllProgress(int Progress)
        {
            sqProgress.SignalQuality = Progress;
        }

        private void UpdateStatus(string str)
        {
            Status.Text = str;
        }

        private void ShowMessage(string str)
        {
            MessageBox.Show(str, "SMS Server Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            Application.Exit();
        }

        private string error_reason = "";

        private void LoadForm(string form_name)
        {
            if (form_name == "MainForm")
            {
                new Mainform().Show();
                this.Hide();
                return;
            }
        }

    }
}
